#include "wx/wxprec.h"
#ifndef WXPRECOMP
#include "wx/brush.h"
#include "wx/dc.h"
#endif

#include "wx/html/forcelnk.h"
#include "wx/html/m_templ.h"
#include "wx/html/htmlcell.h"

FORCE_LINK_ME( m_list )

class wxHtmlListmarkCell : public wxHtmlCell {
  private:
    wxBrush m_Brush;
  public:
    wxHtmlListmarkCell( wxDC *dc, const wxColour& clr );
    void Draw( wxDC& dc, int x, int y, int view_y1, int view_y2,
               wxHtmlRenderingInfo& info );

    DECLARE_NO_COPY_CLASS( wxHtmlListmarkCell )
};

wxHtmlListmarkCell::wxHtmlListmarkCell( wxDC* dc, const wxColour& clr ) : wxHtmlCell(), m_Brush( clr, wxSOLID ) {
  m_Width =  dc->GetCharHeight();
  m_Height = dc->GetCharHeight();
  m_Descent = m_Height / 3;
}



void wxHtmlListmarkCell::Draw( wxDC& dc, int x, int y,
                               int ( view_y1 ), int ( view_y2 ),
                               wxHtmlRenderingInfo& ( info ) ) {
  dc.SetBrush( m_Brush );
  dc.DrawEllipse( x + m_PosX + m_Width / 3, y + m_PosY + m_Height / 3,
                  ( m_Width / 3 ), ( m_Width / 3 ) );
}

struct wxHtmlListItemStruct {
  wxHtmlContainerCell *mark;
  wxHtmlContainerCell *cont;
  int minWidth;
  int maxWidth;
};

class wxHtmlListCell : public wxHtmlContainerCell {
  private:
    wxBrush m_Brush;
    int m_NumRows;
    wxHtmlListItemStruct *m_RowInfo;
    void ReallocRows( int rows );
    void ComputeMinMaxWidths();
    int ComputeMaxBase( wxHtmlCell *cell );
    int m_ListmarkWidth;
  public:
    wxHtmlListCell( wxHtmlContainerCell *parent );
    virtual ~wxHtmlListCell();
    void AddRow( wxHtmlContainerCell *mark, wxHtmlContainerCell *cont );
    virtual void Layout( int w );

    DECLARE_NO_COPY_CLASS( wxHtmlListCell )
};

wxHtmlListCell::wxHtmlListCell( wxHtmlContainerCell *parent ) : wxHtmlContainerCell( parent ) {
  m_NumRows = 0;
  m_RowInfo = 0;
  m_ListmarkWidth = 0;
}

wxHtmlListCell::~wxHtmlListCell() {
  if( m_RowInfo ) {
    free( m_RowInfo );
  }
}

int wxHtmlListCell::ComputeMaxBase( wxHtmlCell *cell ) {
  if( !cell ) {
    return 0;
  }
  wxHtmlCell *child = cell->GetFirstChild();
  while( child ) {
    int base = ComputeMaxBase( child );
    if( base > 0 ) {
      return base + child->GetPosY();
    }
    child = child->GetNext();
  }
  return cell->GetHeight() - cell->GetDescent();
}

void wxHtmlListCell::Layout( int w ) {
  wxHtmlCell::Layout( w );
  ComputeMinMaxWidths();
  m_Width = wxMax( m_Width, wxMin( w, GetMaxTotalWidth() ) );
  int s_width = m_Width - m_IndentLeft;
  int vpos = 0;
  for( int r = 0; r < m_NumRows; r++ ) {
    m_RowInfo[r].mark->Layout( m_ListmarkWidth );
    m_RowInfo[r].cont->Layout( s_width - m_ListmarkWidth );
    const int base_mark = ComputeMaxBase( m_RowInfo[r].mark );
    const int base_cont = ComputeMaxBase( m_RowInfo[r].cont );
    const int adjust_mark = vpos + wxMax( base_cont - base_mark, 0 );
    const int adjust_cont = vpos + wxMax( base_mark - base_cont, 0 );
    m_RowInfo[r].mark->SetPos( m_IndentLeft, adjust_mark );
    m_RowInfo[r].cont->SetPos( m_IndentLeft + m_ListmarkWidth, adjust_cont );
    vpos = wxMax( adjust_mark + m_RowInfo[r].mark->GetHeight(),
                  adjust_cont + m_RowInfo[r].cont->GetHeight() );
  }
  m_Height = vpos;
}

void wxHtmlListCell::AddRow( wxHtmlContainerCell *mark, wxHtmlContainerCell *cont ) {
  ReallocRows( ++m_NumRows );
  m_RowInfo[m_NumRows - 1].mark = mark;
  m_RowInfo[m_NumRows - 1].cont = cont;
}

void wxHtmlListCell::ReallocRows( int rows ) {
  m_RowInfo = ( wxHtmlListItemStruct* ) realloc( m_RowInfo, sizeof( wxHtmlListItemStruct ) * rows );
  m_RowInfo[rows - 1].mark = NULL;
  m_RowInfo[rows - 1].cont = NULL;
  m_RowInfo[rows - 1].minWidth = 0;
  m_RowInfo[rows - 1].maxWidth = 0;
  m_NumRows = rows;
}

void wxHtmlListCell::ComputeMinMaxWidths() {
  if( m_NumRows == 0 ) {
    return;
  }
  m_MaxTotalWidth = 0;
  m_Width = 0;
  for( int r = 0; r < m_NumRows; r++ ) {
    wxHtmlListItemStruct& row = m_RowInfo[r];
    row.mark->Layout( 1 );
    row.cont->Layout( 1 );
    int maxWidth = row.cont->GetMaxTotalWidth();
    int width = row.cont->GetWidth();
    if( row.mark->GetWidth() > m_ListmarkWidth ) {
      m_ListmarkWidth = row.mark->GetWidth();
    }
    if( maxWidth > m_MaxTotalWidth ) {
      m_MaxTotalWidth = maxWidth;
    }
    if( width > m_Width ) {
      m_Width = width;
    }
  }
  m_Width += m_ListmarkWidth + m_IndentLeft;
  m_MaxTotalWidth += m_ListmarkWidth + m_IndentLeft;
}

class wxHtmlListcontentCell : public wxHtmlContainerCell {
  public:
    wxHtmlListcontentCell( wxHtmlContainerCell *p ) : wxHtmlContainerCell( p ) {}
    virtual void Layout( int w ) {
      SetIndent( 0, wxHTML_INDENT_TOP );
      wxHtmlContainerCell::Layout( w );
    }
};

TAG_HANDLER_BEGIN( OLULLI, "OL,UL,LI" )
TAG_HANDLER_VARS
wxHtmlListCell *m_List;
int m_Numbering;
TAG_HANDLER_CONSTR( OLULLI ) {
  m_List = NULL;
  m_Numbering = 0;
}

TAG_HANDLER_PROC( tag ) {
  wxHtmlContainerCell *c;
  if( m_List && tag.GetName() == wxT( "LI" ) ) {
    c = m_WParser->SetContainer( new wxHtmlContainerCell( m_List ) );
    c->SetAlignVer( wxHTML_ALIGN_TOP );
    wxHtmlContainerCell *mark = c;
    c->SetWidthFloat( 2 * m_WParser->GetCharWidth(), wxHTML_UNITS_PIXELS );
    if( m_Numbering == 0 ) {
      c->SetAlignHor( wxHTML_ALIGN_CENTER );
      c->InsertCell( new wxHtmlListmarkCell( m_WParser->GetDC(), m_WParser->GetActualColor() ) );
    } else {
      c->SetAlignHor( wxHTML_ALIGN_RIGHT );
      wxString markStr;
      markStr.Printf( wxT( "%i. " ), m_Numbering );
      c->InsertCell( new wxHtmlWordCell( markStr, *( m_WParser->GetDC() ) ) );
    }
    m_WParser->CloseContainer();
    c = m_WParser->OpenContainer();
    m_List->AddRow( mark, c );
    c = m_WParser->OpenContainer();
    m_WParser->SetContainer( new wxHtmlListcontentCell( c ) );
    if( m_Numbering != 0 ) {
      m_Numbering++;
    }
  } else if( tag.GetName() == wxT( "UL" ) || tag.GetName() == wxT( "OL" ) ) {
    int oldnum = m_Numbering;
    if( tag.GetName() == wxT( "UL" ) ) {
      m_Numbering = 0;
    } else
    { m_Numbering = 1; }
    wxHtmlContainerCell *oldcont;
    oldcont = c = m_WParser->OpenContainer();
    wxHtmlListCell *oldList = m_List;
    m_List = new wxHtmlListCell( c );
    m_List->SetIndent( 2 * m_WParser->GetCharWidth(), wxHTML_INDENT_LEFT );
    ParseInner( tag );
    m_WParser->SetContainer( oldcont );
    m_WParser->CloseContainer();
    m_Numbering = oldnum;
    m_List = oldList;
    return true;
  }
  return false;
}

TAG_HANDLER_END( OLULLI )
TAGS_MODULE_BEGIN( List )
TAGS_MODULE_ADD( OLULLI )
TAGS_MODULE_END( List )
